#ifndef DTWENTYITEM_H
#define DTWENTYITEM_H


#include "dtwenty_global.h"


#include <abstractmodelitem.h>


#include <QSharedData>
#include <QSharedDataPointer>
#include <QString>
#include <QVariant>
#include <QMap>
#include <QMetaType>
#include <QMetaMethod>
#include <QStringList>



class DTWENTYSHARED_EXPORT DTwentyItem : public AbstractModelItem
{
    Q_OBJECT

    Q_PROPERTY(QString name READ name WRITE setName)

    class Data : public QSharedData
    {
    public:
        Data() {}
        Data(const Data& other) : QSharedData(other)
        {
            name = other.name;
        }

        QString name;
    };


public:


    Q_INVOKABLE DTwentyItem(const QString& name = QString(), QObject *parent = 0);
    DTwentyItem(const DTwentyItem& other);

    virtual QVariant value(int field, int role) const;
    virtual bool setValue(int field, const QVariant &value, int role);

    virtual int fieldCount() const;
    virtual QVariant fieldName(int field) const;


    bool operator==(const DTwentyItem& other);
    bool operator==(const QString& name);

    bool operator<(const DTwentyItem& other);
    bool operator<(const QString& name);

    QString name() const;
    void setName(const QString& name);

    virtual int childType() const;


private:

    QExplicitlySharedDataPointer<Data> d;

};


class DTWENTYSHARED_EXPORT DTwentyItemFactory
{
public:

    static DTwentyItem* create(int id, QObject* parent = 0)
    {
        const QMetaObject* mo = QMetaType::metaObjectForType(id);
        if (!mo)
        {
            return 0;
        }


        DTwentyItem* item = qobject_cast<DTwentyItem*>(mo->newInstance());
        item->setParent(parent);

        return item;
    }

    static DTwentyItem* create(const QString& name, int id, QObject* parent = 0)
    {
        DTwentyItem* item = create(id, parent);
        if (!item)
        {
            return 0;
        }
        item->setName(name);

        return item;
    }

};


template<typename ITEM_CLASS>
class DTwentyItemContainer : public DTwentyItem
{
    typedef DTwentyItemContainer<ITEM_CLASS> SelfType;

public:

    typedef QList<ITEM_CLASS*> ItemList;

    Q_INVOKABLE DTwentyItemContainer(const QString& name = QString(), QObject* parent = 0) :
        DTwentyItem(name, parent)
    {
        qRegisterMetaType<ITEM_CLASS*>();
    }

    DTwentyItemContainer(const SelfType& other) :
        DTwentyItem(other)
    {
        qRegisterMetaType<ITEM_CLASS*>();
    }

    virtual int childType() const
    {
        return qMetaTypeId<ITEM_CLASS*>();
    }

    ITEM_CLASS* createChild()
    {
        static QString nameBase = QT_TR_NOOP("New");

        QString itemName = nameBase;
        ItemList itemList = items();
        for (int i = 2; itemList.contains(itemName); i++)
        {
            itemName = QString("%1 (%2)").arg(nameBase).arg(i);
        }

        int type = qMetaTypeId<ITEM_CLASS>();

        return qobject_cast<ITEM_CLASS*>(DTwentyItemFactory::create(itemName, type, this));
    }

    void addItem(const ITEM_CLASS& item)
    {
        foreach (ITEM_CLASS* child, items())
        {
            if (*child == item)
            {
                return;
            }
        }

        ITEM_CLASS* instance = new ITEM_CLASS(item);
        instance->setParent(this);
    }

    void removeItem(int at)
    {
        QList<ITEM_CLASS*> list = items();
        if (at < 0 || at >= list.count())
        {
            return;
        }

        list.at(at)->deleteLater();
    }

    ItemList items() const
    {
        ItemList ret;
        foreach (ITEM_CLASS* item, findChildren<ITEM_CLASS*>("", Qt::FindDirectChildrenOnly))
        {
            ret << item;
        }

        return ret;
    }

};


#endif // DTWENTYITEM_H
